from flask import Flask, request, jsonify
import pymysql
from pymysql.cursors import DictCursor
import traceback
from flask_cors import CORS
from flask_sqlalchemy import SQLAlchemy
import datetime
import uuid
import random
import string
import smtplib
from email.mime.text import MIMEText
from werkzeug.security import generate_password_hash, check_password_hash
import re
import json
import requests
import logging
from sqlalchemy import text

logging.basicConfig(level=logging.DEBUG)

app = Flask(__name__)
CORS(app, resources={
    r"/api/*": {
        "origins": "http://localhost:8080",
        "methods": ["GET", "POST", "PUT", "DELETE", "OPTIONS"],
        "allow_headers": ["Content-Type", "Authorization"],
        "supports_credentials": True,
        "max_age": 86400
    }
})

# 数据库配置
DB_CONFIG = {
    "host": "192.168.118.160",
    "port": 3306,
    "user": "root",
    "password": "root",
    "database": "xiongqin",
    "charset": "utf8mb4"
}

# 配置数据库和安全密钥
app.config['MAIL_SERVER'] = 'smtp.163.com'
app.config['MAIL_PORT'] = 465
app.config['MAIL_USE_SSL'] = True
app.config['MAIL_USERNAME'] = '13594578374@163.com'
app.config['MAIL_PASSWORD'] = 'AXXkRr2Y7EdNwU8E'
app.config['MAIL_DEFAULT_SENDER'] = ('暑假大模型项目', '13594578374@163.com')
app.config[
    'SQLALCHEMY_DATABASE_URI'] = f"mysql+pymysql://{DB_CONFIG['user']}:{DB_CONFIG['password']}@{DB_CONFIG['host']}:{DB_CONFIG['port']}/{DB_CONFIG['database']}?charset={DB_CONFIG['charset']}"
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False
app.config['JSON_SORT_KEYS'] = False
app.config['JSONIFY_PRETTYPRINT_REGULAR'] = False
app.config['REQUESTS_JSON_ALLOW_EMPTY'] = True

# 邮箱配置
MAIL_CONFIG = {
    'smtp_server': 'smtp.163.com',
    'smtp_port': 465,
    'smtp_username': '13594578374@163.com',
    'smtp_password': 'AXXkRr2Y7EdNwU8E',
    'sender': '13594578374@163.com'
}

# 初始化数据库
db = SQLAlchemy(app)

# 星火大模型配置
SPARK_API_KEY = "d7c5529006a0acf0e2f3794cf352bb18:NjhmYjIwYjNjZTIzNGExNjIxYTdjNjQ3"
SPARK_API_URL = "https://spark-api-open.xf-yun.com/v2/chat/completions"


# 定义邮箱验证码模型
class EmailCode(db.Model):
    __tablename__ = 't_email'
    id = db.Column(db.Integer, primary_key=True, autoincrement=True)
    email = db.Column(db.String(255), nullable=False)
    code = db.Column(db.String(255), nullable=False)
    createTime = db.Column(db.DateTime, nullable=False, default=datetime.datetime.now)

    def is_valid(self):
        now = datetime.datetime.now()
        create_time_local = self.createTime.replace(tzinfo=None)
        return (now - create_time_local).total_seconds() < 300


# 定义用户模型
class User(db.Model):
    __tablename__ = 't_user'
    id = db.Column(db.Integer, primary_key=True, autoincrement=True)
    email = db.Column(db.String(120), unique=True, nullable=False)
    pwd = db.Column(db.String(255), nullable=False)

    def set_password(self, password):
        self.pwd = generate_password_hash(password, method='pbkdf2:sha256')

    def check_password(self, password):
        return check_password_hash(self.pwd, password)


# 定义聊天记录模型 - 修复字段类型
class ChatRecord(db.Model):
    __tablename__ = 't_chat'
    id = db.Column(db.Integer, primary_key=True, autoincrement=True)
    session_id = db.Column(db.String(36), nullable=False, comment='会话ID')
    user_type = db.Column(db.Integer, nullable=False, comment='用户类型(1-系统用户 2-普通用户 3-管理员等)')
    content = db.Column(db.Text, nullable=False, comment='消息内容')
    create_time = db.Column(db.DateTime, default=datetime.datetime.now, nullable=False, comment='创建时间')
    status = db.Column(db.Integer, default=1, comment='消息状态(1-正常 0-已删除)')
    message_type = db.Column(db.String(20), default='text', comment='消息类型(text-文本 image-图片等)')
    # 修改字段类型为整数以匹配前端传递的 user.id
    sender_id = db.Column(db.Integer, db.ForeignKey('t_user.id'), nullable=True, comment='发送者ID')
    receiver_id = db.Column(db.Integer, db.ForeignKey('t_user.id'), nullable=True, comment='接收者ID')

    # 外键关联用户表
    sender = db.relationship('User', foreign_keys=[sender_id], backref='sent_messages')
    receiver = db.relationship('User', foreign_keys=[receiver_id], backref='received_messages')


# 创建数据库表
with app.app_context():
    db.create_all()
    print("数据库表创建完成")


# 生成随机验证码
def generate_code(length=6):
    code = ''.join(random.choices(string.digits, k=length))
    print(f"生成验证码：{code}")
    return code


# 发送邮件
def send_email(to_email, subject, content):
    html_content = f"""
    <!DOCTYPE html>
    <html lang="zh-CN">
    <head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <title>验证码 - 暑假大模型项目</title>
        <style>
            body {{
                font-family: 'Arial', sans-serif;
                background-color: #f5f7fa;
                margin: 0;
                padding: 0;
                color: #333;
            }}
            .container {{
                max-width: 600px;
                margin: 20px auto;
                background: white;
                border-radius: 8px;
                overflow: hidden;
                box-shadow: 0 4px 12px rgba(0,0,0,0.1);
            }}
            .header {{
                background: linear-gradient(135deg, #4A6CF7 0%, #2541B2 100%);
                color: white;
                padding: 30px;
                text-align: center;
            }}
            .content {{
                padding: 30px;
            }}
            .code-box {{
                background: #f8f9fa;
                border-radius: 6px;
                padding: 20px;
                text-align: center;
                margin: 25px 0;
                border: 1px dashed #ddd;
            }}
            .code {{
                font-size: 32px;
                font-weight: bold;
                letter-spacing: 5px;
                color: #2541B2;
                margin: 10px 0;
            }}
            .footer {{
                text-align: center;
                padding: 20px;
                font-size: 12px;
                color: #999;
                border-top: 1px solid #eee;
            }}
            .note {{
                font-size: 14px;
                color: #666;
                margin-top: 20px;
            }}
        </style>
    </head>
    <body>
        <div class="container">
            <div class="header">
                <h1>智能配送</h1>
                <p>您的安全验证码</p>
            </div>

            <div class="content">
                <p>尊敬的用户：</p>
                <p>您正在进行账户验证，这是您的验证码：</p>

                <div class="code-box">
                    <div class="code">{content}</div>
                    <p>验证码有效期为5分钟，请尽快完成验证</p>
                </div>

                <div class="note">
                    <p>如果您没有请求此验证码，请忽略此邮件。</p>
                    <p>请勿向任何人分享此验证码。</p>
                </div>
            </div>

            <div class="footer">
                <p>© 2025 暑假大模型项目. 保留所有权利</p>
                <p>如有疑问，请联系: support@summer-ai.com</p>
            </div>
        </div>
    </body>
    </html>
    """

    msg = MIMEText(html_content, 'html', 'utf-8')
    msg['From'] = f"暑假大模型项目 <{MAIL_CONFIG['sender']}>"
    msg['To'] = to_email
    msg['Subject'] = subject

    try:
        with smtplib.SMTP_SSL(MAIL_CONFIG['smtp_server'], MAIL_CONFIG['smtp_port']) as server:
            server.login(MAIL_CONFIG['smtp_username'], MAIL_CONFIG['smtp_password'])
            server.sendmail(MAIL_CONFIG['sender'], [to_email], msg.as_string())
        print(f"邮件发送成功，收件人：{to_email}")
        return True
    except Exception as e:
        print(f"邮件发送失败: {str(e)}")
        return False


# 发送验证码接口
@app.route('/api/send_code', methods=['POST', 'OPTIONS'])
def send_verification_code():
    if request.method == 'OPTIONS':
        return jsonify({})

    data = request.get_json()
    email = data.get('email')
    scene = data.get('scene', 'register')

    if not email:
        return jsonify({'code': 400, 'msg': '邮箱不能为空'}), 400

    if not re.match(r'^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$', email):
        return jsonify({'code': 400, 'msg': '邮箱格式不正确'}), 400

    user = User.query.filter_by(email=email).first()
    if scene == 'register' and user:
        return jsonify({'code': 400, 'msg': '该邮箱已注册，请直接登录'}), 400
    elif scene == 'forgot' and not user:
        return jsonify({'code': 400, 'msg': '该邮箱未注册，请先注册'}), 400

    code = generate_code()

    try:
        EmailCode.query.filter_by(email=email).delete()

        new_code = EmailCode(email=email, code=code)
        db.session.add(new_code)
        db.session.commit()

        if scene == 'register':
            content = f"您的注册验证码是：{code}\n有效期5分钟，请尽快完成注册。"
            subject = "注册验证码"
        else:
            content = f"您的密码重置验证码是：{code}\n有效期5分钟，请尽快完成密码重置。"
            subject = "密码重置验证码"

        if send_email(email, subject, content):
            return jsonify({'code': 200, 'msg': f'验证码已发送，请查收邮件'}), 200
        else:
            db.session.rollback()
            return jsonify({'code': 500, 'msg': '验证码发送失败'}), 500

    except Exception as e:
        db.session.rollback()
        print(f"发送验证码异常: {str(e)}")
        return jsonify({'code': 500, 'msg': '服务器错误'}), 500


# 注册接口
@app.route('/api/register', methods=['POST', 'OPTIONS'])
def register():
    if request.method == 'OPTIONS':
        return jsonify({})

    data = request.get_json()
    required_fields = ['email', 'pwd', 'code']
    if not all(field in data for field in required_fields):
        return jsonify({"code": 400, "msg": "缺少必填字段"}), 400

    try:
        # 验证邮箱是否已注册
        if User.query.filter_by(email=data['email']).first():
            return jsonify({"code": 400, "msg": "该邮箱已注册"}), 400

        # 验证验证码
        email_code = EmailCode.query.filter_by(
            email=data['email'],
            code=data['code']
        ).order_by(EmailCode.createTime.desc()).first()

        if not email_code or not email_code.is_valid():
            return jsonify({"code": 400, "msg": "验证码无效或已过期"}), 400

        # 创建用户
        user = User(email=data['email'])
        user.set_password(data['pwd'])
        db.session.add(user)
        # 删除已使用的验证码
        db.session.delete(email_code)
        db.session.commit()

        return jsonify({"code": 200, "msg": "注册成功"})
    except Exception as e:
        db.session.rollback()
        print(f"注册异常: {str(e)}")
        return jsonify({"code": 500, "msg": "服务器错误"}), 500


# 密码重置接口
@app.route('/api/reset_password', methods=['POST', 'OPTIONS'])
def reset_password():
    if request.method == 'OPTIONS':
        return jsonify({})

    data = request.get_json()
    required_fields = ['email', 'pwd', 'code']
    if not all(field in data for field in required_fields):
        return jsonify({"code": 400, "msg": "缺少必填字段"}), 400

    try:
        user = User.query.filter_by(email=data['email']).first()
        if not user:
            return jsonify({"code": 404, "msg": "用户不存在"}), 404

        email_code = EmailCode.query.filter_by(
            email=data['email'],
            code=data['code']
        ).order_by(EmailCode.createTime.desc()).first()

        if not email_code or not email_code.is_valid():
            return jsonify({"code": 400, "msg": "验证码无效或已过期"}), 400

        user.set_password(data['pwd'])
        db.session.delete(email_code)
        db.session.commit()

        return jsonify({"code": 200, "msg": "密码重置成功，请使用新密码登录"})
    except Exception as e:
        db.session.rollback()
        print(f"重置密码异常: {str(e)}")
        return jsonify({"code": 500, "msg": "服务器错误"}), 500


# 检查邮箱是否已注册
@app.route('/api/check_email', methods=['POST', 'OPTIONS'])
def check_email():
    if request.method == 'OPTIONS':
        return jsonify({})

    data = request.get_json()
    email = data.get('email')

    if not email:
        return jsonify({'code': 400, 'msg': '邮箱不能为空'}), 400

    try:
        user = User.query.filter_by(email=email).first()
        return jsonify({
            'code': 200,
            'isRegistered': user is not None
        })
    except Exception as e:
        print(f"检查邮箱异常: {str(e)}")
        return jsonify({'code': 500, 'msg': '服务器错误'}), 500


# 登录接口
@app.route('/api/login', methods=['POST', 'OPTIONS'])
def login():
    if request.method == 'OPTIONS':
        return jsonify({})

    data = request.get_json()
    required_fields = ['email', 'pwd']
    if not all(field in data for field in required_fields):
        return jsonify({"code": 400, "msg": "缺少必填字段"}), 400

    try:
        user = User.query.filter_by(email=data['email']).first()

        if not user:
            return jsonify({"code": 401, "msg": "用户不存在"}), 401

        password_valid = False
        if check_password_hash(user.pwd, data['pwd']):
            password_valid = True
        elif user.pwd == data['pwd']:
            password_valid = True
            user.set_password(data['pwd'])
            db.session.commit()

        if not password_valid:
            return jsonify({"code": 401, "msg": "密码错误"}), 401

        return jsonify({
            "code": 200,
            "msg": "登录成功",
            "data": {"id": user.id, "email": user.email}
        })
    except Exception as e:
        print(f"登录异常: {str(e)}")
        return jsonify({"code": 500, "msg": "服务器错误"}), 500


# 星火大模型相关函数
def get_answer(messages):
    if not messages:
        return "请提供有效的问题"

    headers = {
        'Authorization': f'Bearer {SPARK_API_KEY}',
        'Content-Type': 'application/json'
    }

    payload = {
        "model": "x1",
        "messages": messages,
        "temperature": 1.2,
        "max_tokens": 32768,
        "stream": False,
        "tools": [{"type": "web_search", "web_search": {"enable": True, "search_mode": "deep"}}]
    }

    try:
        response = requests.post(SPARK_API_URL, headers=headers, json=payload, timeout=60)
        response.raise_for_status()
        result = response.json()

        print(f"星火API响应: {json.dumps(result, indent=2, ensure_ascii=False)}")

        if 'choices' in result and len(result['choices']) > 0:
            return result['choices'][0]['message']['content']
        else:
            print(f"星火API返回无效响应: {result}")
            return "无法获取回答，请重试"

    except Exception as e:
        print(f"调用星火API失败: {str(e)}")
        return f"模型调用失败: {str(e)}"


# 聊天记录保存函数
def saveChat(
        sender_id,
        content,
        session_id,
        user_type=2,
        message_type='text',
        receiver_id=None
):
    try:
        chat = ChatRecord(
            session_id=session_id,
            user_type=user_type,
            content=content,
            sender_id=sender_id,
            receiver_id=receiver_id,
            message_type=message_type,
            status=1
        )
        db.session.add(chat)
        db.session.commit()
        return True
    except Exception as e:
        db.session.rollback()
        print(f"保存聊天记录失败: {str(e)}")
        return False


# 获取特定会话的历史记录
def getChat(session_id):
    try:
        records = ChatRecord.query.filter_by(
            session_id=session_id,
            status=1
        ).order_by(ChatRecord.create_time.asc()).all()

        history = []
        for record in records:
            history.append({
                "role": "user" if record.user_type == 2 else "assistant",
                "content": record.content,
                "message_type": record.message_type,
                "create_time": record.create_time.strftime("%Y-%m-%d %H:%M:%S")
            })
        return history
    except Exception as e:
        print(f"获取聊天记录失败: {str(e)}")
        return []


# 修改后的获取用户会话列表函数 - 使用更可靠的查询方式
def getUserChats(user_id):
    try:
        # 使用原始SQL查询来避免复杂的ORM问题
        sql = text("""
            SELECT 
                session_id,
                MIN(id) AS first_msg_id,
                MAX(create_time) AS last_time
            FROM t_chat
            WHERE (sender_id = :user_id OR receiver_id = :user_id) AND status = 1
            GROUP BY session_id
            ORDER BY last_time DESC
        """)

        result = db.session.execute(sql, {'user_id': user_id}).fetchall()

        chats = []
        for row in result:
            # 获取第一条消息内容
            first_msg = ChatRecord.query.get(row.first_msg_id)
            if not first_msg:
                continue

            title = first_msg.content
            if len(title) > 50:
                title = title[:50] + "..."

            chats.append({
                "session_id": row.session_id,
                "title": title,
                "last_time": row.last_time.strftime("%Y-%m-%d %H:%M:%S")
            })

        return chats

    except Exception as e:
        print(f"获取用户会话列表失败: {str(e)}")
        return []


# 大模型会话接口 - 修复500错误
@app.route('/api/chat', methods=['POST', 'OPTIONS'])
def apiChat():
    if request.method == 'OPTIONS':
        return jsonify({})

    try:
        data = request.get_json()
        content = data.get('content')
        user = data.get('user')
        session_id = data.get('sessionId')

        if not content:
            return jsonify({'code': 400, 'msg': '内容不能为空'}), 400

        if not user or not user.get('id'):
            return jsonify({'code': 400, 'msg': '用户信息缺失'}), 400

        user_id = user['id']

        # 如果session_id为空，创建新的会话ID
        if not session_id:
            session_id = str(uuid.uuid4())

        # 保存用户消息
        saveChat(
            sender_id=user_id,
            content=content,
            session_id=session_id,
            user_type=2,
            receiver_id=None
        )

        # 获取历史消息
        chat_history = getChat(session_id)

        messages = []
        for msg in chat_history:
            role = "user" if msg["role"] == "user" else "assistant"
            messages.append({"role": role, "content": msg["content"]})

        # 检查并限制历史消息长度
        while len(json.dumps(messages)) > 8000 and len(messages) > 1:
            messages.pop(0)

        # 调用模型
        model_response = get_answer(messages)

        # 保存AI回复
        saveChat(
            sender_id=None,
            content=model_response,
            session_id=session_id,
            user_type=1,
            receiver_id=user_id
        )

        return jsonify({
            'code': 200,
            'data': {
                'content': model_response,
                'sessionId': session_id
            }
        })

    except Exception as e:
        print(f'聊天接口出错: {str(e)}')
        return jsonify({'code': 500, 'msg': f'服务器错误: {str(e)}'}), 500


# 获取用户会话列表
@app.route('/api/chats', methods=['GET', 'OPTIONS'])
def getUserChatList():
    if request.method == 'OPTIONS':
        return jsonify({})

    user_id = request.args.get('userId')
    if not user_id:
        return jsonify({'code': 400, 'msg': '缺少用户ID'}), 400

    try:
        # 确保user_id是整数
        user_id = int(user_id)
        chats = getUserChats(user_id)
        return jsonify({
            'code': 200,
            'data': chats
        })
    except Exception as e:
        print(f'获取会话列表错误: {str(e)}')
        return jsonify({'code': 500, 'msg': f'服务器错误: {str(e)}'}), 500


# 获取特定会话的完整记录
@app.route('/api/chat/history', methods=['GET', 'OPTIONS'])
def getChatHistory():
    if request.method == 'OPTIONS':
        return jsonify({})

    session_id = request.args.get('sessionId')
    if not session_id:
        return jsonify({'code': 400, 'msg': '缺少会话ID'}), 400

    try:
        history = getChat(session_id)
        return jsonify({
            'code': 200,
            'data': history
        })
    except Exception as e:
        print(f'获取聊天记录错误: {str(e)}')
        return jsonify({'code': 500, 'msg': f'服务器错误: {str(e)}'}), 500


# 测试路由
@app.route('/api/test_spark', methods=['GET'])
def test_spark():
    try:
        test_message = [{"role": "user", "content": "你好，请介绍一下自己"}]
        response = get_answer(test_message)
        return jsonify({"code": 200, "response": response})
    except Exception as e:
        return jsonify({"code": 500, "error": str(e), "traceback": traceback.format_exc()})


if __name__ == '__main__':
    app.run(host='0.0.0.0', port=9000, debug=True)